package com.black.common.utils;

import cn.hutool.core.lang.UUID;
import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.black.common.core.domain.R;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Log4j2
public class OSSUtils {

    //地域
    private static String endpoint = "http://oss-cn-chengdu.aliyuncs.com";
    // 阿里云 主/子 账号AccessKey拥有所有API的访问权限
    private static String accessKeyId = "LTAI5tR2EKDVzZxrPgxF7uqQ";
    private static String accessKeySecret = "geSbXqBfanqbPSFs5p2OF5i7YVahHu";
    //存储空间
    private static String bucketName = "exerciseapp";

    // 主机
    private static String host = "https://exerciseapp.oss-cn-chengdu.aliyuncs.com/";

    /**
     * 获取阿里云OSS客户端对象
     *
     * return ossClient
     */
    public static OSSClient  getOssclient(){
        //设置超时机制和重试机制
        ClientConfiguration conf = new ClientConfiguration();
        conf.setConnectionTimeout(5000);
        conf.setMaxErrorRetry(3);

        return  new OSSClient(endpoint, accessKeyId, accessKeySecret, conf);
    }

    /**
     * 创建存储空间
     * <p>
     * param ossClient OSS连接
     * param bucketName 存储空间
     * return
     */
    public static String createBucketName(String bucketName) {
        OSSClient ossClient=getOssclient();
        // 存储空间
        final String bucketNames = bucketName;
        if (!ossClient.doesBucketExist(bucketName)) {
            // 创建存储空间
            Bucket bucket = ossClient.createBucket(bucketName);
            log.info("创建存储空间成功");
            ossClient.shutdown();
            return bucket.getName();
        }
        return bucketNames;
    }

    /**
     * 删除存储空间buckName
     * <p>
     * param ossClient oss对象
     * param bucketName 存储空间
     */
    public static void deleteBucket(String bucketName) {
        OSSClient ossClient=getOssclient();
        ossClient.deleteBucket(bucketName);
        ossClient.shutdown();
        log.info("删除" + bucketName + "Bucket成功");
    }

    /**
     * 创建模拟文件夹
     * <p>
     * param ossClient oss连接
     * param bucketName 存储空间
     * param folder 模拟文件夹名如"zhangsan"
     * return 文件夹名
     */
    public static String createFolder(String bucketName, String folder, OSSClient ossClient) {
        // 文件夹名
        final String folderName = folder;
        // 判断文件夹是否存在，不存在则创建
        if (!ossClient.doesObjectExist(bucketName, folderName)) {
            // 创建文件夹
            ossClient.putObject(bucketName, folderName, new ByteArrayInputStream(new byte[0]));
            log.info("创建文件夹成功");
            // 得到文件夹名
            OSSObject object = ossClient.getObject(bucketName, folderName);
            String fileDir = object.getKey();
            return fileDir;
        }
        return folderName;
    }

    /**
     * 根据key删除OSS服务器上的文件
     * <p>
     * param ossClient oss连接
     * param bucketName 存储空间
     * param folder 模拟文件夹名 如"zhangsan/"
     * param key Bucket下的文件的路径名+文件名 如："upload/cake.jpg"
     *
     * @return
     */
    public static R deleteFile(String path) {
        OSSClient ossClient=getOssclient();
        // 去掉path的域名
        path = path.replace(host, "");
        VoidResult voidResult = ossClient.deleteObject(bucketName, path);
//        log.info("删除" + bucketName + "下的文件" + path + "成功");

        int statusCode = voidResult.getResponse().getStatusCode();
        if (voidResult.getResponse().getStatusCode() != 204) {
            return R.fail(statusCode);
        }
        ossClient.shutdown();
        return R.ok(statusCode);
    }

    /**
     * 上传本地文件至OSS
     * <p>
     * param ossClient oss连接
     * param file 上传文件（文件全路径如：D:\\image\\cake.jpg）
     * param bucketName 存储空间
     * param storePath 模拟文件夹名（父目录-所属模块） 如"zhangsan/"
     * return String 返回的唯一MD5数字签名
     */
    public static R uploadObjectOSS(String storePath, MultipartFile file) throws IOException {
        OSSClient ossClient=getOssclient();
        InputStream is = file.getInputStream();
        String resultStr = null;
        storePath += "/";
        createFolder(bucketName, storePath,ossClient);
        try {
            // 文件名
            String fileName = file.getOriginalFilename();
            // 文件大小
            // Long fileSize = file.length();
            Long fileSize = file.getSize();
            // 创建上传Object的Metadata
            ObjectMetadata metadata = new ObjectMetadata();
            // 上传的文件的长度
            metadata.setContentLength(is.available());
            // 指定该Object被下载时的网页的缓存行为
            metadata.setCacheControl("no-cache");
            // 指定该Object下设置Header
            metadata.setHeader("Pragma", "no-cache");
            // 指定该Object被下载时的内容编码格式
            metadata.setContentEncoding("utf-8");
            // 文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，
            // 如果没有扩展名则填默认值application/octet-stream
            // metadata.setContentType(getContentType(fileName));
            String contentType = getContentType(fileName);
            if ( contentType.length() == 0) {
                return R.fail("上传文件类型有误，支持的图片格式包括\\\"JPG\\\", \\\"JPEG\\\", \\\"PNG\\\" ");
            } else {
                metadata.setContentType(contentType);
            }
            // 指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）
            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
            // 仓库文件名
             String fileExtension = fileName.substring(fileName.lastIndexOf("."));
            fileName = UUID.randomUUID().toString(true)+fileExtension;
            // 上传文件 (上传文件流的形式)
            PutObjectResult putResult = ossClient.putObject(bucketName, storePath + fileName, is, metadata);
            // 解析结果
            resultStr = host + storePath + fileName;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
        } finally {
            // 关闭流
            if (is != null) {
                is.close();
            }
            ossClient.shutdown();
            // 关闭OSSClient
            // ossclient.shutdown();
        }
        return R.ok(resultStr);
    }

    /**
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
     * <p>
     * param fileName 文件名
     * return 文件的contentType
     */
    public static String getContentType(String fileName) {
        // 文件的后缀名
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
        if (".bmp".equalsIgnoreCase(fileExtension)) {
//            return "image/bmp";
            return "";
        }
        if (".gif".equalsIgnoreCase(fileExtension)) {
//            return "image/gif";
            return "";
        }
        if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
                || ".png".equalsIgnoreCase(fileExtension)) {
//            return "image/jpeg";
            return "image/jpg";
        }
        if (".png".equalsIgnoreCase(fileExtension)) {
            return "image/png";
        }
        if (".html".equalsIgnoreCase(fileExtension)) {
//            return "text/html";
            return "";
        }
        if (".txt".equalsIgnoreCase(fileExtension)) {
//            return "text/plain";
            return "";
        }
        if (".vsd".equalsIgnoreCase(fileExtension)) {
//            return "application/vnd.visio";
            return "";
        }
        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
//            return "application/vnd.ms-powerpoint";
            return "";
        }
        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
//            return "application/msword";
            return "";
        }
        if (".xml".equalsIgnoreCase(fileExtension)) {
//            return "text/xml";
            return "";
        }
        // 默认返回类型
        return "";
    }

    /**
     * 下载文件到本地
     *
     * @param ossFilePath 上传到OSS起的全路径名
     * @param filename    文件下载到本地保存的路径
     */
    public static void downloadFile(String ossFilePath, String filename) {
        OSSClient ossClient=getOssclient();
        ossClient.getObject(new GetObjectRequest(bucketName, ossFilePath), new File(filename));
        ossClient.shutdown();
    }

}
